package com.zjitc.service.imp;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;
import com.zjitc.common.Gsonal;
import com.zjitc.vo.Inventory;
import com.zjitc.vo.PageModel;
import com.zjitc.common.ServerResponse;
import com.zjitc.common.redis.RedisCache;
import com.zjitc.dao.ExpressDao;
import com.zjitc.dao.OrderDao;
import com.zjitc.dao.ProductDao;
import com.zjitc.pojo.*;
import com.zjitc.service.OrderService;
import com.zjitc.utils.RedisAuto;
import com.zjitc.utils.Utils;
import com.zjitc.vo.order.OrderInfo;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeoutException;

/**
 * Create By IntelliJ IDEA
 *
 * @author: myq
 * @create-Time: 2017/11/23  14:49
 */
@SuppressWarnings("ALL")
@Lazy(false)
@Service
public class OrderServiceImpl implements OrderService {

  @Autowired
  private OrderDao dao;
  @Autowired
  private ProductDao pdao;
  @Autowired
  private ExpressDao edao;
  @Autowired
  private ConnectionFactory factory;
  @Autowired
  private RedisCache redis;
  @Autowired
  private ExpressServiceImpl expressService;

  /**
   * 交换机
   */
  private final String EXCHANGE_NAME = "Exchange_BigWork";
  private final Integer PAGE_SIZE = 5;
  private final String REDIS_PRODUCT = "products";
  private final String INVENTORY = "inventory";
  private final String ORDER = "order";
  private final String ADD = "add";
  private final String DEL = "del";
  private final String UPDATE_PRODUCT = "updateproduct";
  private final String UPDATE_ORDER = "updateorder";
  private final String ALLORDER = "allorder";
  private static Logger log = Logger.getLogger(OrderServiceImpl.class);


  /**
   * 使用数据库操作的代码是 Orders order = dao.findOrderByoid(oid); List<Orderitems> orderitem =
   * dao.findOrderitem(oid); for (Orderitems i : orderitem) { Product product =
   * pdao.findbypid(i.getPid()); i.setProduct(product); i.setSubtotal(product.getShop_price() *
   * i.getCount()); } order.setOrderitems(orderitem);
   */
  @Override
  public Orders findOrderFromRedis(String uid, String oid) {
    String json = redis.hashMapget(uid, oid);
    Orders orders = Gsonal.fromJson(json, Orders.class);
    return orders;
  }

  @Override
  public ServerResponse deleteorder(String key, String oid) {
    try {
      redis.delHash(key, oid);
      Connection connection = factory.newConnection();
      Channel channel = connection.createChannel();
      OrderInfo orderInfo = new OrderInfo(oid);
      String tojson = Gsonal.tojson(orderInfo);
      channel.basicPublish(EXCHANGE_NAME, DEL, MessageProperties.PERSISTENT_TEXT_PLAIN,
          tojson.getBytes());
      System.out.println("添加到rabbit的删除队列中");
      channel.close();
      connection.close();
      return ServerResponse.createSuccess("1");
    } catch (Exception e) {
      e.printStackTrace();
      return ServerResponse.createSuccess("0");
    }
  }

  @Override
  public int deleteAllorder(String uid) {
    List<Orders> orders = redis.hashListGetAll(uid, Orders.class);
    redis.del(uid);
    final int[] i = {0};
    orders.forEach(order -> {
      dao.deleteorderitem(order.getOid());
      edao.delete(order.getOid());
      dao.deleteorder(order.getOid());
      i[0]++;
    });
    return i[0];
  }

  @Override
  public void update(User user, Orders order) throws SQLException {
    redis.hashset(user.getUid(), order.getOid(), Gsonal.tojson(order));
    try (Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();) {
      channel.basicPublish(EXCHANGE_NAME, UPDATE_ORDER, MessageProperties.PERSISTENT_TEXT_PLAIN,
          Gsonal.tojson(order).getBytes());
    } catch (TimeoutException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * 添加order到队列
   */
  @Override
  public ServerResponse<Orders> addorder(User user, List<Caritem> caritems) {

    boolean b = hasinventory(caritems);
    if (b == false) {
      return ServerResponse.createError("0");
    }
    try (Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();) {

      //后台创建一个订单模板
      Orders orders = createOrder(caritems, user);
      //存入缓存
      redis.hashset(user.getUid(), orders.getOid(), Gsonal.tojson(orders));
      //将订单模板放入队列
      OrderInfo orderInfo = new OrderInfo(orders);
      String tojson = Gsonal.tojson(orderInfo);
      channel.basicPublish(EXCHANGE_NAME, ADD, MessageProperties.PERSISTENT_TEXT_PLAIN,
          tojson.getBytes());
      System.out.println("添加到了rabbitmq的Add 队列中");
      return ServerResponse.createSuccess(orders);
    } catch (Exception e) {
      e.printStackTrace();
      return ServerResponse.createError("0");
    }

  }

  @Override
  public Orders createOrder(List<Caritem> caritemList, User user) {
    Orders orders = new Orders();
    orders.setOid(Utils.getUUID());
    orders.setOrdertime(new Date());
    orders.setState(0);
    orders.setName(user.getName());
    orders.setTelephone(user.getTelephone());
    orders.setUid(user.getUid());
    List<Orderitems> products = new ArrayList<>();
    double totalprice = 0.0;
    for (Caritem item : caritemList) {
      Orderitems orderitems = new Orderitems();
      orderitems.setItemid(Utils.getUUID());
      orderitems.setCount(item.getCount());
      orderitems.setPid(item.getProduct().getPid());
      orderitems.setOid(orders.getOid());
      orderitems.setProduct(item.getProduct());
      orderitems.setSubtotal(item.getPrice() * item.getCount());
      products.add(orderitems);
      totalprice += item.getPrice();
    }
    orders.setOrderitems(products);
    orders.setTotal(totalprice);
    return orders;
  }

  @Override
  public List<Caritem> createOrderitem(String pid, String count) {
    Product product = pdao.findbypid(pid);
    List<Caritem> caritems = new ArrayList<>();
    int i = Integer.parseInt(count);
    caritems.add(new Caritem(product, i, product.getShopPrice() * i));
    return caritems;
  }

  @Override
  public void judgeandupdate(HttpSession session) {
    Orders orders = (Orders) session.getAttribute(ORDER);
    User user = (User) session.getAttribute("user");
    if (orders != null) {
      //说明没有存进数据库
      redis.hashset(user.getUid(), orders.getOid(), Gsonal.tojson(orders));
      session.removeAttribute(ORDER);
      try (Connection connection = factory.newConnection();
          Channel channel = connection.createChannel();) {
        String tojson = Gsonal.tojson(new OrderInfo(orders));
        channel.basicPublish(EXCHANGE_NAME, ADD, MessageProperties.PERSISTENT_TEXT_PLAIN,
            tojson.getBytes());
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      } catch (TimeoutException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  @Override
  public PageModel<Orders> findAllOrder(Integer pageid, int count) {
    checkredisAll();
    List<Orders> ordersList = redis.hashListGetAll(ALLORDER, Orders.class);
    PageModel info = new PageModel(ordersList, count, pageid);
    return info;
  }

  /**
   * 发货
   */
  @Override
  public void shipments(String oid) {
    Orders orders = findOrderbyoid(oid);
    orders.setState(2);
    try {
      Express check = expressService.check(oid);
      if (check == null) {
        expressService.add(oid);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    redis.hashset(orders.getUid(), orders.getOid(), Gsonal.tojson(orders));
    dao.update(orders);
  }

  private Orders findOrderbyoid(String oid) {
    Orders orders = dao.findOrderByoid(oid);
    List<Orderitems> orderitems = dao.findOrderitem(oid);
    orderitems.forEach(orderitem -> {
      Product product = pdao.findbypid(orderitem.getPid());
      orderitem.setProduct(product);
    });
    orders.setOrderitems(orderitems);
    return orders;
  }

  @Override
  public void expcheck(String oid) {

  }

  /**
   * 收货
   */
  @Override
  public void confirm(User user, String oid) {
    Orders orders = redis.hashgetObject(user.getUid(), oid, Orders.class);
    orders.setState(3);
    redis.hashset(user.getUid(), oid, Gsonal.tojson(orders));
    dao.update(orders);
  }

  @Override
  public boolean hasinventory(String pid, String count) {
    Inventory inventory = redis.hashgetObject(INVENTORY, pid, Inventory.class);
    if (inventory.getInventory() - Integer.parseInt(count) >= 0) {
      return true;
    }
    return false;
  }

  @Override
  public void updateinventory(List<Orderitems> orderitems, String type) {
    orderitems.forEach(item -> {
      Inventory inventory = redis.hashgetObject(INVENTORY, item.getPid(), Inventory.class);
      Product product = redis.hashgetObject(REDIS_PRODUCT, item.getPid(), Product.class);
      String pay = "pay";
      String refund = "refund";
      if (pay.equals(type)) {
        inventory.setInventory(inventory.getInventory() - item.getCount());
      } else if (refund.equals(type)) {
        inventory.setInventory(inventory.getInventory() + item.getCount());
      }
      product.setInventory(inventory.getInventory());
      redis.hashset(INVENTORY, item.getPid(), Gsonal.tojson(inventory));
      redis.hashset(REDIS_PRODUCT, product.getPid(), Gsonal.tojson(product));
      try (Connection connection = factory.newConnection();
          Channel channel = connection.createChannel()) {
        channel.basicPublish(EXCHANGE_NAME, UPDATE_PRODUCT, MessageProperties.PERSISTENT_TEXT_PLAIN,
            Gsonal.tojson(product).getBytes());
      } catch (IOException e) {
        e.printStackTrace();
      } catch (TimeoutException e) {
        e.printStackTrace();
      }
    });
  }

  @Override
  public PageModel<Orders> findPageByUid(String uid, int pageid) {
    checkredis(uid);
    checkinventory();
    List<Orders> ordersList = redis.hashListGetAll(uid, Orders.class);
    PageModel pageModel = new PageModel(ordersList, PAGE_SIZE, pageid);
    return pageModel;
  }

  private void checkinventory() {
    if (!redis.exists(INVENTORY)) {
      RedisAuto.inventoryRedis(pdao, redis, INVENTORY);
    }
  }

  private void checkredis(String uid) {
    if (!redis.exists(uid)) {
      RedisAuto.orderRedis(dao, pdao, redis, uid);
    }
  }

  private void checkredisAll() {
    RedisAuto.orderRedisAll(dao, pdao, redis, ALLORDER);
  }

  private boolean hasinventory(List<Caritem> caritems) {
    int flag = 0;
    for (Caritem caritem : caritems) {
      Inventory inventory = redis
          .hashgetObject(INVENTORY, caritem.getProduct().getPid(), Inventory.class);
      if (inventory.getInventory() - caritem.getCount() <= 0) {
        return false;
      }
    }
    return true;
  }
}
